package mgodb

import (
	"fmt"
	"jgt-oper/src/model"
	"jgt-oper/src/schema"
	"jgt-oper/src/service/mongo"
	"time"

	"github.com/facebookgo/inject"
	"github.com/globalsign/mgo"
	"github.com/globalsign/mgo/bson"
	"github.com/pkg/errors"
)

// cPark 建筑管理
const cPark = "oper_park"

// Park 建筑节点管理
type Park struct {
	DB *mongo.DB
}

// Init 初始化
func (a *Park) Init(g *inject.Graph, db *mongo.DB) {
	a.DB = db

	// 初始化mongo索引
	a.DB.C(cPark, func(c *mgo.Collection) error {
		c.EnsureIndex(mgo.Index{
			Key:    []string{"record_id"},
			Unique: true,
		})
		c.EnsureIndexKey("_id")
		c.EnsureIndexKey("level_code")
		c.EnsureIndexKey("deleted")
		return nil
	})

	var val model.IPark = a
	g.Provide(&inject.Object{Value: val, Name: "IPark"})
}

// QueryPage 查询分页数据
func (a *Park) QueryPage(params schema.ParkQueryParam, pageIndex, pageSize uint) (int64, []*schema.Park, error) {
	query := bson.M{
		"deleted": 0,
	}

	if v := params.Type; v != 0 {
		query["type"] = v
	}

	if v := params.ParentID; v != "" {
		item, _ := a.Get(v)
		if item != nil {
			query["level_code"] = bson.M{"$regex": fmt.Sprintf("^%s.+", item.LevelCode)}
		}
	}

	if v := params.Name; v != "" {
		query["name"] = bson.M{"$regex": v}
	}

	var total int64
	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		n, err := c.Find(query).Count()
		if err != nil {
			return err
		}
		total = int64(n)
		if total == 0 {
			return nil
		}

		return c.Find(query).Sort("type", "id").Skip(int((pageIndex - 1) * pageSize)).Limit(int(pageSize)).All(&items)
	})
	if err != nil {
		return 0, nil, errors.Wrapf(err, "查询分页数据发生错误")
	}

	return total, items, nil
}

// QuerySelect 查询选择数据
func (a *Park) QuerySelect(params schema.ParkSelectParam) ([]*schema.ParkSelect, error) {
	query := bson.M{
		"deleted": 0,
	}

	if v := params.Search; v != "" {
		query["name"] = bson.M{"$regex": v}
	}

	if v := params.Name; v != "" {
		query["name"] = v
	}

	if v := params.ParentID; params.Type != 10 {

		query["parent_id"] = v
	}

	if v := params.Type; v > 0 {
		query["type"] = v
	}

	if v := params.LeaseStatus; v > 0 {
		query["lease_status"] = v
	}

	if v := params.SalesStatus; v > 0 {
		query["sales_status"] = v
	}

	var items []*schema.ParkSelect
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("_id").All(&items)
	})

	if err != nil {
		return nil, errors.Wrapf(err, "查询选择数据发生错误")
	}
	return items, nil
}

// QueryByParentIDOrderLevelCode 根据上级查询数据
func (a *Park) QueryByParentIDOrderLevelCode(parentID string) ([]*schema.Park, error) {
	query := bson.M{
		"deleted":   0,
		"parent_id": parentID,
	}

	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("level_code").All(&items)
	})
	if err != nil {
		return nil, errors.Wrapf(err, "根据上级查询数据发生错误")
	}

	return items, nil
}

// Get 精确查询数据
func (a *Park) Get(recordID string) (*schema.Park, error) {
	var item schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(bson.M{"record_id": recordID}).One(&item)
	})
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, errors.Wrapf(err, "精确查询数据发生错误")
	}
	return &item, nil
}

// CheckChild 检查下级菜单
func (a *Park) CheckChild(parentID string) (bool, error) {
	var exists bool
	query := bson.M{
		"deleted":   0,
		"parent_id": parentID,
	}

	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		n, err := c.Find(query).Count()
		if err != nil {
			return err
		}
		exists = n > 0
		return nil
	})
	if err != nil {
		return false, errors.Wrapf(err, "检查下级菜单发生错误")
	}

	return exists, nil
}

// GetByCodeAndType 根据编号和类型查询数据
func (a *Park) GetByCodeAndType(code string, typ int) (*schema.Park, error) {
	var item schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(bson.M{"deleted": 0, "status": 1, "code": code, "type": typ}).One(&item)
	})
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, errors.Wrapf(err, "根据编号和类型查询数据发生错误")
	}
	return &item, nil
}

//	QueryChildByLevelCode 根据分级码查询下级数据
func (a *Park) QueryChildByLevelCode(levelCode string) ([]*schema.Park, error) {
	query := bson.M{
		"deleted":    0,
		"status":     1,
		"level_code": bson.M{"$regex": fmt.Sprintf("^%s.+", levelCode)},
	}

	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("sequence").All(&items)
	})
	if err != nil {
		return nil, errors.Wrapf(err, "查询选择数据发生错误")
	}
	return items, nil
}

//	Create 创建数据
func (a *Park) Create(item *schema.Park) error {
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		id, err := a.DB.IncrID(cPark)
		if err != nil {
			return err
		}
		item.ID = id
		return c.Insert(item)
	})
	if err != nil {
		return errors.Wrapf(err, "创建数据发生错误")
	}

	return nil
}

//	Update 更新数据
func (a *Park) Update(recordID string, info map[string]interface{}) error {
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Update(bson.M{"record_id": recordID}, bson.M{"$set": info})
	})
	if err != nil {
		return errors.Wrapf(err, "更新数据发生错误")
	}
	return nil
}

//	Delete 删除数据
func (a *Park) Delete(recordID string) error {
	info := map[string]interface{}{
		"deleted": time.Now().Unix(),
	}
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Update(bson.M{"record_id": recordID}, bson.M{"$set": info})
	})
	if err != nil {
		return errors.Wrapf(err, "删除数据发生错误")
	}
	return nil
}

//	UpdateLevelCode 更新分级码数据
func (a *Park) UpdateLevelCode(src, target string) error {
	query := bson.M{
		"deleted":    0,
		"level_code": bson.M{"$regex": "^" + src},
	}

	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("level_code").All(&items)
	})
	if err != nil {
		return errors.Wrapf(err, "更新分级码数据发生错误")
	}

	err = a.DB.C(cPark, func(c *mgo.Collection) error {
		b := c.Bulk()

		for _, item := range items {
			levelCode := target
			if len(item.LevelCode) > len(target) {
				levelCode = fmt.Sprintf("%s%s", levelCode, []byte(item.LevelCode)[len(target):])
			}
			b.Update(bson.M{"_id": item.ID}, bson.M{"$set": bson.M{"level_code": levelCode}})
		}

		_, verr := b.Run()
		return verr
	})
	if err != nil {
		return errors.Wrapf(err, "更新分级码数据发生错误")
	}

	return nil
}

//	QueryByIDs 根据ID列表查询菜单数据
func (a *Park) QueryByIDs(recordIDs []string) ([]*schema.Park, error) {
	query := bson.M{
		"deleted":   0,
		"status":    1,
		"record_id": bson.M{"$in": recordIDs},
	}

	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).All(&items)
	})
	if err != nil {
		return nil, errors.Wrapf(err, "根据ID列表查询菜单数据发生错误")
	}

	return items, nil
}

// QueryAllNodes 查询园区和区域信息，作为基础数据，用于页面呈现
func (a *Park) QueryAllNodes() ([]*schema.Park, error) {
	query := bson.M{
		"deleted":    0,
		"level_code": bson.M{"$regex": "^.{0,5}$"},
	}
	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {

		return c.Find(query).Sort("id").Skip(0).Limit(50).All(&items)
	})
	if err != nil {
		return nil, errors.Wrapf(err, "查询园区和区域数据发生错误")
	}

	return items, nil
}

// QueryChildrenNodes 查询所有的所有的子节点
func (a *Park) QueryChildrenNodes(levelCode string) ([]*schema.Park, error) {
	//{'level_code':{'$regex':'^0101010101.{0,3}$'}}
	i := 12 - len(levelCode) + 1
	s := fmt.Sprintf("^%s.{1,%d}$", levelCode, i)
	query := bson.M{
		"deleted":    0,
		"level_code": bson.M{"$regex": s},
	}
	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("id").Skip(0).Limit(1000).All(&items)
	})
	if err != nil {
		return nil, err
	}
	return items, nil
}

// QueryDirectChildrenNodes 查询所有的直接子节点
func (a *Park) QueryDirectChildrenNodes(recordID string) ([]*schema.Park, error) {

	query := bson.M{
		"deleted":   0,
		"parent_id": recordID,
	}
	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("level_code").Skip(0).Limit(1000).All(&items)
	})
	if err != nil {
		return nil, err
	}
	return items, nil
}

// QueryNodesByLevelCode 根据分级码查询节点
func (a *Park) QueryNodesByLevelCode(levelCode string) ([]*schema.Park, error) {
	query := bson.M{
		"deleted":    0,
		"level_code": bson.M{"$regex": levelCode},
	}
	var items []*schema.Park
	err := a.DB.C(cPark, func(c *mgo.Collection) error {
		return c.Find(query).Sort("level_code").Skip(0).Limit(1000).All(&items)
	})
	if err != nil {
		return nil, err
	}
	return items, nil
}
